﻿/*
filename: debugnew.cpp
This is used to substitute a version of the new operator that
can be used for debugging memory leaks. In any (all?) code
files #include debugnew.h. Add debugnew.cpp to the project.
*/
#include "GLLInc.h"

#ifdef GLL_NEW_DEL

#define LOG_FILE_NAME "./Trace.NewDelete.log"

using namespace std;
#include "USRNEW.h"

class EntryDNT 
{
public:
	EntryDNT (void* ptr, char const* file, int line, int size){
		_ptr = ptr;
		_file = file;
		_line = line;
		_size = size;
		_count = 0;
	}
	EntryDNT(){
		_ptr = 0;
		_file = "";
		_line = 0;
		_size = 0;
		_count = 0;
	}
	char const* _file;
	int _line;
	int _size;
	void* _ptr;
	int _count;
};

class FileLineIndex
{
public:
	const char* _pFile;
	int _line;
	FileLineIndex(const char* file, int line){_pFile = file; _line = line;}
};

bool operator < (const FileLineIndex& l, const FileLineIndex& r)
{
	if(l._pFile == r._pFile){
		return l._line < r._line;
	}
	return (l._pFile < r._pFile);
}

class LockerDNT
{
	int count;
public:
	bool Locked(){return count > 0;}
	void Lock(){++count;}
	void Unlock(){--count;}
};

class DebugNewTracer  
{
public:
	DebugNewTracer ();
	~DebugNewTracer ();
	void Add (void* p, const char* file, int line, size_t size);
	void Remove (void* p);
	void Dump ();

private:
	typedef std::map<void*, EntryDNT> Ptr2EntryMap;
	typedef std::map<FileLineIndex, unsigned int> FL2EntryMap;
	Ptr2EntryMap _map;
	FL2EntryMap _fileMap;
	size_t _totalsize;
	FILE* _logfp;
	LockerDNT _locker;
};

#pragma init_seg(compiler)
DebugNewTracer _dbgNewTrace;

void DebugNewTrace_Add (void* p, const char* file, int line, size_t size)
{
	try{
		_dbgNewTrace.Add(p, file, line, size);
	}catch(...){
		//悄悄的
	}
}
void DebugNewTrace_Remove (void* p)
{//悄悄的
	try{
		_dbgNewTrace.Remove(p);
	}catch(...){
		//悄悄的
	}
}


DebugNewTracer::DebugNewTracer ()
{
	_totalsize = 0;
	
	if(! fopen_s(&_logfp, LOG_FILE_NAME,"wt") )
	{
		return;
	} 
}

void DebugNewTracer::Add (void* p, const char* file, int line, size_t size)
{
	file = ( (strrchr(file,'\\') == NULL) ?  file : strrchr(file,'\\') + 1);

	while(_locker.Locked());
	_locker.Lock();

	EntryDNT& ent = _map[p];

	ent._count++;
	ent._file = file;
	ent._line = line;
	ent._ptr = p;
	ent._size = size;

	FileLineIndex fli(file, line);
	unsigned int& cnt = _fileMap[fli];
	cnt++;

	_locker.Unlock();

	_totalsize += size;
}

void DebugNewTracer::Remove (void* p)
{
	const char* file = 0;
	int line = 0;

	while(_locker.Locked());
	_locker.Lock();

	Ptr2EntryMap::iterator it = _map.find (p);
	if (it != _map.end ())
	{
		EntryDNT& ent = it->second;
		_totalsize -= ent._size;
		ent._count--;
		file = ent._file;
		line = ent._line;
		if(ent._count<=0)
		{
			_map.erase (it);
		}
	}

	FileLineIndex fli(file, line);
	FL2EntryMap::iterator itfl = _fileMap.find(fli);
	if(itfl != _fileMap.end())
	{
		unsigned int& cnt = itfl->second;
		cnt--;
		if(cnt <= 0)
		{
			_fileMap.erase(itfl);
		}
	}

	_locker.Unlock();

}

DebugNewTracer::~DebugNewTracer ()
{
	Dump ();
	fclose(_logfp);
}

void DebugNewTracer::Dump ()
{
	if(!_logfp)return;

	if(_fileMap.size())
	{
		fprintf(_logfp, "unfree size: %d\n", _totalsize);
		fflush(_logfp);

		for (FL2EntryMap::iterator it = _fileMap.begin (); it != _fileMap.end (); ++it)
		{
			const FileLineIndex& fli = it->first;
			unsigned int cnt = it->second;
			fprintf(_logfp, "%s(%d) X%d\n", fli._pFile, fli._line, cnt);
			fflush(_logfp);
		}		
	}
	
	if (_map.size () )
	{
		fprintf(_logfp, "--------------------------------------------------------------\n");
		fprintf(_logfp, "unfree size: %d\n", _totalsize);
		fflush(_logfp);

		for (Ptr2EntryMap::iterator it = _map.begin (); it != _map.end (); ++it)
		{
			EntryDNT& ent = it->second;
			char const * file = ent._file;
			int line = ent._line;
			int size = ent._size;
			void* ptr = ent._ptr;
			int count = ent._count;

			fprintf(_logfp,"%s(%d) 0x%p(%d) X%d\n", file, line, ptr, size, count);
			fflush(_logfp);
		}
	}

}

#endif GLL_NEW_DEL
